<template>
  <div class="box-top" v-if="showToolBar">
    <div class="box-top-left" v-if="false">
      <div class="box-top-left-button">
        <a-input
          @change="searchAll"
          v-model:value="search"
          placeholder="搜索日志"
          prefix-icon="search"
          size="small"
          style="width: 200px"
          allowClear
        />
        <div class="box-top-left-button-group">
          <a-button type="primary" @click="searchAll" size="small">查找</a-button>
          <a-button type="primary" @click="searchPrevious" size="small">上一个</a-button>
          <a-button type="primary" @click="searchNext" size="small">下一个</a-button>
        </div>
      </div>
    </div>
    <div
      class="box-top-right"
      :style="{
        color:
          socketStatus == WebSocketStatus.CLOSING
            ? '#ff6600'
            : socketStatus == WebSocketStatus.OPEN
            ? '#33ff33'
            : '#e6371c',
      }"
    >
      {{
        socketStatus == WebSocketStatus.CLOSING
          ? '正在连接中...'
          : socketStatus == WebSocketStatus.OPEN
          ? '已连接'
          : '断开连接'
      }}
    </div>
  </div>
  <div ref="terminal" class="terminal-container"></div>
</template>

<script setup lang="ts">
import { debounce } from 'lodash';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { SearchAddon } from '@xterm/addon-search';
import '@xterm/xterm/css/xterm.css';
import { WebSocketService } from '@/utils/websocket.service';
import { WebSocketStatus } from '@/enums/commonEnum';

const props = defineProps({
  url: {
    type: String,
  },
  showToolBar: {
    type: Boolean,
    default: false,
  },
});

const emits = defineEmits(['listenerSocketStatus']);
const search = ref<string>('');
const wsService = ref<any>(null);
const terminal = ref<any>(null);
const fitAddon = new FitAddon();
const searchAddon = new SearchAddon();
const socketStatus = ref<number | string>(WebSocketStatus.CONNECTING);
let terminalSocket = ref<any>(null);
let term = ref<any>(null);

onMounted(() => {
  if (props.url) {
    wsService.value = new WebSocketService(`ws://${location.host}${props.url}`);
    initWS();
    initTerm();
    onTerminalResize();
  }
});
// 初始化WS
const initWS = () => {
  if (!terminalSocket.value) {
    createWS();
  }
  if (wsService.value && wsService.value.readyState == 0) {
    wsService.value.disconnect();
    createWS();
  }
};

// 创建WS
const createWS = () => {
  wsService.value.connect();
  // 监听 WebSocket 的消息事件
  wsService.value?.onMessage((data: any) => {
    socketStatus.value = wsService.value.readyState;
    if (data === 'ping') {
      // 接收到心跳消息，回复 "pong"
      wsService.value.send('pong');
      return false;
    }
    term.value.write(data + '\r\n');
    term.value.element && term.value.focus();
  });

  wsService.value?.onclose((data: any) => {
    socketStatus.value = wsService.value.readyState;
    term.value.write(`断开连接: ${data}`);
  });
};

// 关闭socket
const closeWS = () => {
  wsService.value && wsService.value.disconnect();
};

// 初始化Terminal
const initTerm = () => {
  term.value = new Terminal({
    lineHeight: 1.2,
    fontSize: 16,
    fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
    theme: {
      background: '#202746',
    },
    cursorBlink: false,
    cursorStyle: 'block',
    disableStdin: true,
    tabStopWidth: 4,
  });
  nextTick(() => {
    term.value.clear();
    term.value.open(terminal.value);
    term.value.loadAddon(searchAddon);
    term.value.loadAddon(fitAddon);
  });
  // 不能初始化的时候fit,需要等terminal准备就绪,可以设置延时操作
  setTimeout(() => {
    fitAddon.fit();
  }, 5);
};

// 适应浏览器尺寸变化
const fitTerm = () => {
  fitAddon.fit();
};
const onResize = debounce(() => {
  fitTerm();
}, 500);
const onTerminalResize = () => {
  window.addEventListener('resize', onResize);
};
const removeResizeListener = () => {
  window.removeEventListener('resize', onResize);
};

// 搜索日志
const searchAll = () => {
  searchAddon.findNext(search.value);
};

// 上一个
const searchPrevious = () => {
  searchAddon.findPrevious(search.value);
};

// 下一个
const searchNext = () => {
  searchAddon.findNext(search.value);
};

onBeforeUnmount(() => {
  removeResizeListener();
  wsService.value && wsService.value.disconnect();
});

watch(
  () => socketStatus.value,
  (newVal) => {
    emits('listenerSocketStatus', newVal);
  },
  { deep: true },
);

defineExpose({
  closeWS,
});
</script>

<style scoped>
.box-top {
  width: 100%;
  height: 46px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: rgb(58, 51, 51);
  color: rgb(255, 254, 255);
  font-weight: 500;
  padding: 0 20px;
  .box-top-left {
    display: flex;
    align-items: center;
    .box-top-left-button {
      display: flex;
      .box-top-left-button-group {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-left: 8px;
      }
    }
  }
  .box-top-right {
    font-size: 14px;
    font-weight: 600;
  }
}
.terminal-container {
  width: 100%;
  height: 100%;
  background: #202746;
}
</style>
